package com.sky.skyopsserver.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sky.skyopsserver.domain.Application;
import com.sky.skyopsserver.domain.Project;
import com.sky.skyopsserver.enums.ResponseCodeEnum;
import com.sky.skyopsserver.exception.BizException;
import com.sky.skyopsserver.mapper.ApplicationMapper;
import com.sky.skyopsserver.mapper.ProjectMapper;
import com.sky.skyopsserver.service.ProjectService;
import com.sky.skyopsserver.vos.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.YearMonth;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 项目信息服务实现类
 * 
 * @author Administrator
 * @description 针对表【project(项目信息表)】的数据库操作Service实现
 * @createDate 2025-09-13 17:43:03
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project>
        implements ProjectService {

    private final ApplicationMapper applicationMapper;
    
    // 项目编码格式正则表达式
    private static final Pattern CODE_PATTERN = Pattern.compile("^[a-zA-Z][a-zA-Z0-9_-]*$");

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addProject(ProjectAddReqVO reqVO) {
        log.info("开始添加项目，项目编码: {}, 项目名称: {}", reqVO.getCode(), reqVO.getName());
        
        // 验证项目编码格式
        if (!validateProjectCode(reqVO.getCode())) {
            throw new BizException(ResponseCodeEnum.PROJECT_CODE_INVALID);
        }
        
        // 检查项目编码是否已存在
        if (checkProjectCodeExists(reqVO.getCode(), null)) {
            throw new BizException(ResponseCodeEnum.PROJECT_CODE_EXISTS);
        }
        
        // 检查项目名称是否已存在
        if (checkProjectNameExists(reqVO.getName(), null)) {
            throw new BizException(ResponseCodeEnum.PROJECT_NAME_EXISTS);
        }
        
        // 构建项目实体
        Project project = Project.builder()
                .code(reqVO.getCode())
                .name(reqVO.getName())
                .remark(reqVO.getRemark())
                .createTime(LocalDateTime.now())
                .build();
        
        // 保存到数据库
        boolean saved = save(project);
        if (!saved) {
            throw new BizException(ResponseCodeEnum.PROJECT_ADD_FAILED);
        }
        
        log.info("项目添加成功，项目ID: {}", project.getId());
        return project.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateProject(ProjectUpdateReqVO reqVO) {
        log.info("开始更新项目，项目ID: {}", reqVO.getId());
        
        // 检查项目是否存在
        Project existingProject = getById(reqVO.getId());
        if (Objects.isNull(existingProject)) {
            throw new BizException(ResponseCodeEnum.PROJECT_NOT_EXISTS);
        }
        
        // 验证项目编码格式
        if (!validateProjectCode(reqVO.getCode())) {
            throw new BizException(ResponseCodeEnum.PROJECT_CODE_INVALID);
        }
        
        // 检查项目编码是否已被其他项目使用
        if (checkProjectCodeExists(reqVO.getCode(), reqVO.getId())) {
            throw new BizException(ResponseCodeEnum.PROJECT_CODE_EXISTS);
        }
        
        // 检查项目名称是否已被其他项目使用
        if (checkProjectNameExists(reqVO.getName(), reqVO.getId())) {
            throw new BizException(ResponseCodeEnum.PROJECT_NAME_EXISTS);
        }
        
        // 更新项目信息
        Project project = new Project();
        BeanUtils.copyProperties(reqVO, project);
        
        boolean updated = updateById(project);
        if (!updated) {
            throw new BizException(ResponseCodeEnum.PROJECT_UPDATE_FAILED);
        }
        
        log.info("项目更新成功，项目ID: {}", reqVO.getId());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteProject(Long id) {
        log.info("开始删除项目，项目ID: {}", id);
        
        // 检查项目是否存在
        Project existingProject = getById(id);
        if (Objects.isNull(existingProject)) {
            throw new BizException(ResponseCodeEnum.PROJECT_NOT_EXISTS);
        }
        
        // 检查项目下是否有应用
        Long applicationCount = getApplicationCountByProjectId(id);
        if (applicationCount > 0) {
            throw new BizException(ResponseCodeEnum.PROJECT_HAS_APPLICATIONS);
        }
        
        boolean deleted = removeById(id);
        if (!deleted) {
            throw new BizException(ResponseCodeEnum.PROJECT_DELETE_FAILED);
        }
        
        log.info("项目删除成功，项目ID: {}", id);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchDeleteProject(List<Long> ids) {
        log.info("开始批量删除项目，项目ID列表: {}", ids);
        
        if (CollectionUtils.isEmpty(ids)) {
            throw new BizException(ResponseCodeEnum.PARAM_NOT_VALID);
        }
        
        // 检查所有项目是否存在
        List<Project> existingProjects = listByIds(ids);
        if (existingProjects.size() != ids.size()) {
            throw new BizException(ResponseCodeEnum.PROJECT_NOT_EXISTS);
        }
        
        // 检查项目下是否有应用
        Map<Long, Long> applicationCountMap = getApplicationCountByProjectIds(ids);
        List<Long> projectsWithApps = applicationCountMap.entrySet().stream()
                .filter(entry -> entry.getValue() > 0)
                .map(Map.Entry::getKey)
                .toList();
        
        if (!projectsWithApps.isEmpty()) {
            throw new BizException(ResponseCodeEnum.PROJECT_HAS_APPLICATIONS);
        }
        
        boolean deleted = removeByIds(ids);
        if (!deleted) {
            throw new BizException(ResponseCodeEnum.PROJECT_DELETE_FAILED);
        }
        
        log.info("项目批量删除成功，删除数量: {}", ids.size());
        return true;
    }

    @Override
    public ProjectRspVO getProjectById(Long id) {
        log.info("查询项目详情，项目ID: {}", id);
        
        Project project = getById(id);
        if (Objects.isNull(project)) {
            throw new BizException(ResponseCodeEnum.PROJECT_NOT_EXISTS);
        }
        
        ProjectRspVO rspVO = new ProjectRspVO();
        BeanUtils.copyProperties(project, rspVO);
        
        // 设置应用数量
        Long applicationCount = getApplicationCountByProjectId(id);
        rspVO.setApplicationCount(applicationCount);
        
        return rspVO;
    }

    @Override
    public ProjectDetailRspVO getProjectDetailById(Long id) {
        log.info("查询项目详情（包含应用列表），项目ID: {}", id);
        
        Project project = getById(id);
        if (Objects.isNull(project)) {
            throw new BizException(ResponseCodeEnum.PROJECT_NOT_EXISTS);
        }
        
        ProjectDetailRspVO rspVO = new ProjectDetailRspVO();
        BeanUtils.copyProperties(project, rspVO);
        
        // 查询应用列表
        List<Application> applications = applicationMapper.selectList(new LambdaQueryWrapper<Application>()
                .eq(Application::getProjectId, id)
                .orderByAsc(Application::getName));
        
        List<ProjectDetailRspVO.ApplicationSimpleInfo> applicationInfos = applications.stream()
                .map(application -> ProjectDetailRspVO.ApplicationSimpleInfo.builder()
                        .id(application.getId())
                        .code(application.getCode())
                        .name(application.getName())
                        .remark(application.getRemark())
                        .createTime(application.getCreateTime())
                        .build())
                .collect(Collectors.toList());
        
        rspVO.setApplications(applicationInfos);
        rspVO.setApplicationCount((long) applicationInfos.size());
        
        return rspVO;
    }

    @Override
    public IPage<ProjectRspVO> getProjectPage(ProjectPageReqVO reqVO) {
        log.info("分页查询项目列表，查询条件: {}", reqVO);
        
        // 构建分页对象
        Page<Project> page = new Page<>(reqVO.getCurrent(), reqVO.getSize());
        
        // 构建查询条件
        LambdaQueryWrapper<Project> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.hasText(reqVO.getCode()), Project::getCode, reqVO.getCode())
                   .like(StringUtils.hasText(reqVO.getName()), Project::getName, reqVO.getName())
                   .like(StringUtils.hasText(reqVO.getRemark()), Project::getRemark, reqVO.getRemark())
                   .orderByDesc(Project::getCreateTime);
        
        // 执行分页查询
        IPage<Project> projectPage = page(page, queryWrapper);
        
        // 获取所有项目的应用数量
        List<Long> projectIds = projectPage.getRecords().stream()
                .map(Project::getId)
                .collect(Collectors.toList());
        Map<Long, Long> applicationCountMap = getApplicationCountByProjectIds(projectIds);
        
        // 转换为响应VO
        IPage<ProjectRspVO> rspPage = projectPage.convert(project -> {
            ProjectRspVO rspVO = new ProjectRspVO();
            BeanUtils.copyProperties(project, rspVO);
            rspVO.setApplicationCount(applicationCountMap.getOrDefault(project.getId(), 0L));
            return rspVO;
        });
        
        log.info("分页查询项目列表完成，总记录数: {}", rspPage.getTotal());
        return rspPage;
    }

    @Override
    public List<ProjectOptionRspVO> getAllProjectOptions() {
        log.info("查询所有项目选项");
        
        List<Project> projects = list(new LambdaQueryWrapper<Project>()
                .orderByAsc(Project::getCode));
        
        // 获取所有项目的应用数量
        List<Long> projectIds = projects.stream()
                .map(Project::getId)
                .collect(Collectors.toList());
        Map<Long, Long> applicationCountMap = getApplicationCountByProjectIds(projectIds);
        
        return projects.stream()
                .map(project -> convertToOptionVO(project, applicationCountMap.getOrDefault(project.getId(), 0L)))
                .collect(Collectors.toList());
    }

    @Override
    public List<ProjectOptionRspVO> getProjectOptionsWithApps() {
        log.info("查询有应用的项目选项");
        
        // 先获取有应用的项目ID
        List<Long> projectIdsWithApps = applicationMapper.selectList(new LambdaQueryWrapper<Application>()
                        .select(Application::getProjectId)
                        .groupBy(Application::getProjectId))
                .stream()
                .map(Application::getProjectId)
                .collect(Collectors.toList());
        
        if (CollectionUtils.isEmpty(projectIdsWithApps)) {
            return new ArrayList<>();
        }
        
        List<Project> projects = listByIds(projectIdsWithApps);
        Map<Long, Long> applicationCountMap = getApplicationCountByProjectIds(projectIdsWithApps);
        
        return projects.stream()
                .map(project -> convertToOptionVO(project, applicationCountMap.getOrDefault(project.getId(), 0L)))
                .sorted(Comparator.comparing(ProjectOptionRspVO::getCode))
                .collect(Collectors.toList());
    }

    @Override
    public List<ProjectOptionRspVO> getEmptyProjectOptions() {
        log.info("查询空项目选项");
        
        // 获取所有项目
        List<Project> allProjects = list();
        
        // 获取有应用的项目ID
        Set<Long> projectIdsWithApps = applicationMapper.selectList(new LambdaQueryWrapper<Application>()
                        .select(Application::getProjectId)
                        .groupBy(Application::getProjectId))
                .stream()
                .map(Application::getProjectId)
                .collect(Collectors.toSet());
        
        // 过滤出空项目
        return allProjects.stream()
                .filter(project -> !projectIdsWithApps.contains(project.getId()))
                .map(project -> convertToOptionVO(project, 0L))
                .sorted(Comparator.comparing(ProjectOptionRspVO::getCode))
                .collect(Collectors.toList());
    }

    @Override
    public ProjectStatisticsRspVO getProjectStatistics() {
        log.info("获取项目统计信息");
        
        // 项目总数
        long totalCount = count();
        
        // 应用总数
        long totalApplicationCount = applicationMapper.selectCount(new LambdaQueryWrapper<>());
        
        // 有应用的项目数量
        long projectsWithAppsCount = applicationMapper.selectList(new LambdaQueryWrapper<Application>()
                        .select(Application::getProjectId)
                        .groupBy(Application::getProjectId))
                .size();
        
        // 空项目数量
        long emptyProjectsCount = totalCount - projectsWithAppsCount;
        
        // 本月新增项目数量
        YearMonth currentMonth = YearMonth.now();
        LocalDateTime monthStart = currentMonth.atDay(1).atStartOfDay();
        LocalDateTime monthEnd = currentMonth.atEndOfMonth().atTime(23, 59, 59);
        
        long monthlyAddedCount = count(new LambdaQueryWrapper<Project>()
                .between(Project::getCreateTime, monthStart, monthEnd));
        
        // 平均每项目应用数
        double avgAppsPerProject = totalCount > 0 ? (double) totalApplicationCount / totalCount : 0.0;
        
        return ProjectStatisticsRspVO.builder()
                .totalCount(totalCount)
                .projectsWithAppsCount(projectsWithAppsCount)
                .emptyProjectsCount(emptyProjectsCount)
                .monthlyAddedCount(monthlyAddedCount)
                .totalApplicationCount(totalApplicationCount)
                .avgAppsPerProject(Math.round(avgAppsPerProject * 100.0) / 100.0)
                .build();
    }

    @Override
    public Boolean checkProjectCodeExists(String code, Long excludeId) {
        LambdaQueryWrapper<Project> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Project::getCode, code);
        
        if (Objects.nonNull(excludeId)) {
            queryWrapper.ne(Project::getId, excludeId);
        }
        
        return count(queryWrapper) > 0;
    }

    @Override
    public Boolean checkProjectNameExists(String name, Long excludeId) {
        LambdaQueryWrapper<Project> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Project::getName, name);
        
        if (Objects.nonNull(excludeId)) {
            queryWrapper.ne(Project::getId, excludeId);
        }
        
        return count(queryWrapper) > 0;
    }

    @Override
    public ProjectRspVO getProjectByCode(String code) {
        log.info("根据编码查询项目，项目编码: {}", code);
        
        Project project = getOne(new LambdaQueryWrapper<Project>()
                .eq(Project::getCode, code));
        
        if (Objects.isNull(project)) {
            throw new BizException(ResponseCodeEnum.PROJECT_NOT_EXISTS);
        }
        
        ProjectRspVO rspVO = new ProjectRspVO();
        BeanUtils.copyProperties(project, rspVO);
        
        // 设置应用数量
        Long applicationCount = getApplicationCountByProjectId(project.getId());
        rspVO.setApplicationCount(applicationCount);
        
        return rspVO;
    }

    @Override
    public List<ProjectRspVO> searchProjectByName(String name) {
        log.info("根据名称模糊查询项目，关键字: {}", name);
        
        List<Project> projects = list(new LambdaQueryWrapper<Project>()
                .like(StringUtils.hasText(name), Project::getName, name)
                .orderByAsc(Project::getCode));
        
        return convertToRspVOList(projects);
    }

    @Override
    public List<ProjectRspVO> searchProjectByCode(String code) {
        log.info("根据编码模糊查询项目，关键字: {}", code);
        
        List<Project> projects = list(new LambdaQueryWrapper<Project>()
                .like(StringUtils.hasText(code), Project::getCode, code)
                .orderByAsc(Project::getCode));
        
        return convertToRspVOList(projects);
    }

    @Override
    public Long getApplicationCountByProjectId(Long projectId) {
        return applicationMapper.selectCount(new LambdaQueryWrapper<Application>()
                .eq(Application::getProjectId, projectId));
    }

    @Override
    public Map<Long, Long> getApplicationCountByProjectIds(List<Long> projectIds) {
        if (CollectionUtils.isEmpty(projectIds)) {
            return new HashMap<>();
        }
        
        // 查询每个项目的应用数量
        List<Application> applications = applicationMapper.selectList(new LambdaQueryWrapper<Application>()
                .select(Application::getProjectId)
                .in(Application::getProjectId, projectIds));
        
        // 统计每个项目的应用数量
        Map<Long, Long> applicationCountMap = applications.stream()
                .collect(Collectors.groupingBy(Application::getProjectId, Collectors.counting()));
        
        // 确保所有项目都有记录，没有应用的项目设置为0
        projectIds.forEach(projectId -> applicationCountMap.putIfAbsent(projectId, 0L));
        
        return applicationCountMap;
    }

    @Override
    public Boolean validateProjectCode(String code) {
        return StringUtils.hasText(code) && CODE_PATTERN.matcher(code).matches();
    }

    @Override
    public List<String> getAllProjectCodes() {
        log.info("获取所有项目编码列表");
        
        return baseMapper.selectList(new LambdaQueryWrapper<Project>()
                        .select(Project::getCode)
                        .orderByAsc(Project::getCode))
                .stream()
                .map(Project::getCode)
                .collect(Collectors.toList());
    }

    @Override
    public List<String> getAllProjectNames() {
        log.info("获取所有项目名称列表");
        
        return baseMapper.selectList(new LambdaQueryWrapper<Project>()
                        .select(Project::getName)
                        .orderByAsc(Project::getName))
                .stream()
                .map(Project::getName)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean moveApplicationsToProject(List<Long> applicationIds, Long targetProjectId) {
        log.info("移动应用到指定项目，应用ID列表: {}, 目标项目ID: {}", applicationIds, targetProjectId);
        
        if (CollectionUtils.isEmpty(applicationIds)) {
            throw new BizException(ResponseCodeEnum.PARAM_NOT_VALID);
        }
        
        // 检查目标项目是否存在
        Project targetProject = getById(targetProjectId);
        if (Objects.isNull(targetProject)) {
            throw new BizException(ResponseCodeEnum.PROJECT_NOT_EXISTS);
        }
        
        // 检查应用是否存在
        List<Application> applications = applicationMapper.selectByIds(applicationIds);
        if (applications.size() != applicationIds.size()) {
            throw new BizException(ResponseCodeEnum.APPLICATION_NOT_EXISTS);
        }
        
        // 更新应用的项目信息
        applications.forEach(application -> {
            application.setProjectId(targetProjectId);
            application.setProjectName(targetProject.getName());
        });
        
        // 批量更新
        applications.forEach(applicationMapper::updateById);
        
        log.info("应用移动成功，移动数量: {}", applicationIds.size());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean removeApplicationsFromProject(List<Long> applicationIds, Long projectId) {
        log.info("从项目中移除应用，应用ID列表: {}, 项目ID: {}", applicationIds, projectId);
        
        if (CollectionUtils.isEmpty(applicationIds)) {
            throw new BizException(ResponseCodeEnum.PARAM_NOT_VALID);
        }
        
        // 检查应用是否属于指定项目
        List<Application> applications = applicationMapper.selectList(new LambdaQueryWrapper<Application>()
                .in(Application::getId, applicationIds)
                .eq(Application::getProjectId, projectId));
        
        if (applications.size() != applicationIds.size()) {
            throw new BizException(ResponseCodeEnum.APPLICATION_NOT_IN_PROJECT);
        }
        
        // 这里可以设置为默认项目或者设置为null，根据业务需求决定
        // 暂时设置为null
        applications.forEach(application -> {
            application.setProjectId(null);
            application.setProjectName(null);
        });
        
        // 批量更新
        applications.forEach(applicationMapper::updateById);
        
        log.info("应用移除成功，移除数量: {}", applicationIds.size());
        return true;
    }

    /**
     * 转换为选项VO
     * 
     * @param project 项目实体
     * @param applicationCount 应用数量
     * @return 选项VO
     */
    private ProjectOptionRspVO convertToOptionVO(Project project, Long applicationCount) {
        return ProjectOptionRspVO.builder()
                .id(project.getId())
                .code(project.getCode())
                .name(project.getName())
                .applicationCount(applicationCount)
                .remark(project.getRemark())
                .build();
    }

    /**
     * 转换为响应VO列表
     * 
     * @param projects 项目列表
     * @return 响应VO列表
     */
    private List<ProjectRspVO> convertToRspVOList(List<Project> projects) {
        // 获取应用数量
        List<Long> projectIds = projects.stream()
                .map(Project::getId)
                .collect(Collectors.toList());
        Map<Long, Long> applicationCountMap = getApplicationCountByProjectIds(projectIds);
        
        return projects.stream()
                .map(project -> {
                    ProjectRspVO rspVO = new ProjectRspVO();
                    BeanUtils.copyProperties(project, rspVO);
                    rspVO.setApplicationCount(applicationCountMap.getOrDefault(project.getId(), 0L));
                    return rspVO;
                })
                .collect(Collectors.toList());
    }
}




